/*
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *
 *   版权所有  2014-2015 成都星锐蓝海网络科技有限公司
 *   商业许可请联系  +86-18682011860    QQ:66442834
 *   
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include "xyz_log.h"
#include "wmpctrl.h"
#include "udphelp.h"
#include "wtpinfo.h"
#include "wtpnl.h"
#include "util.h"
#include "global.h"


extern int G_wmpsock;
extern int G_nlksock;
extern struct sockaddr_in G_wmpaddr;


static int wmpWaitRecvAC(int fd);
static int wmpWaitRecvNL(int fd);

static int wmpWaitReconnReq(void);
static int wmpWaitRcvAll(int to);

void wmpWait(int *state)
{
	int i = 0;
	int rc;
//	system("/sbin/ns_led.sh active &");
	if (wtpInfoSendHookPause2Krn()) {
		xyz_log_error("Pause HOOK error");
	}
	for (i = 0; i < 60; ++i) {
		wmpWaitReconnReq();
		rc = wmpWaitRcvAll(5);
		if (0 == rc) {
			xyz_log_warn("Reconnect ac ok, jump status to run!!!");
			if (wtpInfoSendHookRestart2Krn()) {
				xyz_log_error("Restart HOOK error");
			}
			*state = WTP_STATE_RUN;
			return;
		} else if (1 == rc) {
			break;
		} else {
			continue;
		}
	}
	xyz_log_error("Wait status timeout, after 3s, jump status to disc!");
	sleep(3);
	*state = WTP_STATE_DSCV;
}

/*
 *
 */
static int wmpWaitReconnReq(void)
{
	WMMSG msg;
	uint16_t seqnum = 0;
	uint8_t *apid = NULL;

//	apid = (uint8_t *)nsap_deid_get_byte();
        apid = (uint8_t *)devid;
	seqnum = wtpInfoGetSEQNUM();
	if (wmmClearInit(&msg, apid, seqnum, WMM_CODE_RECONN_REQ)) {
		xyz_log_error("Message head INIT error");
		return -1;
	}
	if (udpSend(G_wmpsock, msg.buff, msg.offset, &G_wmpaddr) < 1) {
		xyz_log_error("func(%s), send message failed, %s",
				__FUNCTION__, strerror(errno));
		return -1;
	}
	return 0;
}

/*
 *
 */
static int wmpWaitRcvAll(int to)
{
	int rc = 0;
	fd_set fset;
	struct timeval tv;
	int max_fd = G_wmpsock > G_nlksock ? G_wmpsock : G_nlksock;

	tv.tv_sec = to;
	tv.tv_usec = 0;

	do {
		FD_ZERO(&fset);
		FD_SET(G_wmpsock, &fset);
		FD_SET(G_nlksock, &fset);
		rc = select(max_fd + 1, &fset, NULL, NULL, &tv);
		if (rc > 0) {
			if (FD_ISSET(G_wmpsock, &fset)) {
				if (0 == wmpWaitRecvAC(G_wmpsock)) {
					return 0;
				}
			}
			if (FD_ISSET(G_nlksock, &fset)) {
				wmpWaitRecvNL(G_nlksock);
			}
		}
	} while (rc > 0);

	return -1;
}


/*
 *
 */
static int wmpWaitRecvAC(int fd)
{
	WMMSG msg;
	struct sockaddr_in from;
	int len = 0;
	BUFF attr;
	uint32_t rescode = 0;

	memset(&msg, 0, sizeof(msg));
	memset(&from, 0, sizeof(from));
	len = udpRecv(fd, msg.buff, WMM_BUFF_SIZE, &from);
	if (len < 1) {
		xyz_log_error("recvfrom : %s", strerror(errno));
		return -1;
	}
	msg.totlen = len;
	if (wmmPrepRecvd(&msg)) {
		xyz_log_error("Preprocess message error");
		return -1;
	}
	if (WMM_CODE_REBOOT_REQ == msg.code) {
		uint16_t seqnum = 0;
		uint8_t *apid = NULL;
//		apid = (uint8_t *) nsap_deid_get_byte();
                apid = (uint8_t *)devid;
		seqnum = wtpInfoGetSEQNUM();
		if (wmmClearInit(&msg, apid, seqnum, WMM_CODE_REBOOT_REP)) {
			xyz_log_error("Message head INIT error");
			return -1;
		}
		if (udpSend(G_wmpsock, msg.buff, msg.offset, &G_wmpaddr) < 1) {
			xyz_log_error("sendto : %s", strerror(errno));
			return -1;
		}
		xyz_log_debug("Send REBOOT-REP message");
		return 1;
	}
	if (WMM_CODE_RECONN_REP == msg.code) {
		if (1 == wmmGetAttr(&msg, &attr)) {
			if (WMM_ATTR_RESCODE == attr.type) {
				if (wmmParseResCode(&attr, &rescode)) {
					xyz_log_error("Parse RESULT-CODE error");
					return -1;
				} else {
					if (WMM_RESULT_CODE_OK == rescode) {
						return 0;
					}
				}
			}
		}
	}
	return -1;
}




/*
 *
 */
static int wmpWaitRecvNL(int fd)
{
	int len = 0;
	NLBUFF nlmsg = NLBUFF_INIT;

	len = recv(fd, nlmsg.buff, NL_SELF_SIZE, 0);
	if (len < 1 ) {
		xyz_log_error("recv : %s", strerror(errno));
		return -1;
	}
	return 0;
}
